using System.Collections;
using System.Collections.Generic;


[System.Xml.Serialization.XmlRootAttribute("lists", Namespace = "")]
public class SvnInfoLists
{
	public class entry
	{
		public class Commit
		{
			[System.Xml.Serialization.XmlAttribute()]
			public int revision;
		}

		public string name;
		public Commit commit;
		[System.Xml.Serialization.XmlAttribute()]
		public string kind;

		public bool isFile()
		{
			return kind == "file";
		}
	}

	public class EntryList: List<entry>
	{
//		[System.Xml.Serialization.XmlAttribute()]
//		public string path;
	}

	public EntryList list;

}

public static class SvnTool
{
    static string GetSvnPath()
    {
        if(System.IO.File.Exists("/usr/local/bin/svn"))
        {
            return "/usr/local/bin/svn";
        }
        else
        {
            return "svn";
        }
    }

	public static Dictionary<string, int> GetSvnInfo(HashSet<string> paths, out string err, string otherParams = null)
	{
		HashSet<string> dirs = new HashSet<string>();
		foreach (var path in paths)
		{
            if (System.IO.Directory.Exists(path))
            {
                dirs.Add(path);
            }
            else
            {
                dirs.Add(System.IO.Path.GetDirectoryName(path));
            }
		}

		HashSet<string> tempSet = new HashSet<string>(dirs);

		foreach (var s in tempSet)
		{
			string dir = s;
			do
			{
				dir = System.IO.Path.GetDirectoryName(dir);
				if(dirs.Contains(dir))
				{
					dirs.Remove(s);
					break;
				}
			}
			while(!string.IsNullOrEmpty(dir));
		}

		Dictionary<string, int> result = new Dictionary<string, int>();
		err = null;

//		string log = dirs.Count + "\n";
//		foreach (var d in dirs)
//		{
//			log += d + "\n";
//		}
//		UnityEngine.Debug.LogError(log);

		foreach (var path in dirs)
		{
			Dictionary<string, int> temp = GetSvnInfo(path, out err, otherParams);
			if (!string.IsNullOrEmpty(err))
			{
				err = "GetSvnInfo failed: " + path + "\n" + err;
				return null;
			}

			if (temp != null)
			{
				foreach (var entry in temp)
				{
					result.Add(entry.Key, entry.Value);
				}
			}
		}

		return result;
	}

	public static Dictionary<string, int> GetSvnInfo(string path, out string err, string otherParams = null)
	{
		if (!System.IO.Directory.Exists(path))
		{
			err = null;
			return null;
		}

		string output = null;
        err = null;
//		err = CommandLineTool.cmdWithOutput("pwd", "", ref output);
//		UnityEngine.Debug.LogError("pwd: " + output);

		int exitCode = CommandLineTool.CmdWithOutput(GetSvnPath(), "ls --xml -R \"" + path + "\" " + otherParams, ref output, ref err);
        if (exitCode != 0)
		{
			return null;
		}
		string str = output;

		System.IO.StringReader strReader = new System.IO.StringReader(str);
		System.Xml.Serialization.XmlSerializer xmldes = new System.Xml.Serialization.XmlSerializer(typeof(SvnInfoLists));
		SvnInfoLists info = xmldes.Deserialize(strReader) as SvnInfoLists;

		Dictionary<string, int> result = new Dictionary<string, int>();
		foreach (var t in info.list)
		{
			result.Add(path + "/" + t.name, t.commit.revision);
		}
		return result;
	}

    public static HashSet<string> GetModifiedFileSet(int comparedSvnVersion, string otherParams = null)
    {
        HashSet<string> modifiedPathSet = new HashSet<string>();
        string output = null;
        string err = null;
        int exitCode = CommandLineTool.CmdWithOutput(GetSvnPath(), "info --show-item last-changed-revision", ref output, ref err);
        if (exitCode != 0)
        {
            throw new System.Exception(err);
        }
        int lastChangedVersion = int.Parse(output);



        string output2 = null;
        string err2 = null;
        int exitCode2 = CommandLineTool.CmdWithOutput(GetSvnPath(), "info --show-item relative-url", ref output2, ref err2);
        if (exitCode2 != 0)
        {
            throw new System.Exception(err2);
        }
        output2 = output2.Replace("\n", "");

        if (output2.EndsWith("\r"))
        {
            output2 = output2.Substring(0, output2.Length - 1);
        }
        string needRemovePath = output2.Substring(1, output2.Length - 1) + "/";




        int oldConfigVersion = comparedSvnVersion;

        //            Debug.LogError("test svn2: " + lastChangedVersion + "  " + oldConfigVersion);
        if (oldConfigVersion != lastChangedVersion)
        {
            if (lastChangedVersion > oldConfigVersion)
            {
                oldConfigVersion++;
            }
            else
            {
                oldConfigVersion--;
            }

            exitCode = CommandLineTool.CmdWithOutput(GetSvnPath(), "log -r " + lastChangedVersion + ":" + oldConfigVersion + " . -v " + otherParams, ref output, ref err);



            if (exitCode != 0)
            {
                throw new System.Exception(err);
            }

            //                Debug.LogError("test svn: " + output);

            System.Text.RegularExpressions.Regex regex = new System.Text.RegularExpressions.Regex(@"^[ ]+.[ ]+(.*)");


            System.IO.StringReader strReader = new System.IO.StringReader(output);
            while (true)
            {
                string line = strReader.ReadLine();
                if (line == null)
                {
                    break;
                }

                System.Text.RegularExpressions.Match match = regex.Match(line);
                if (match.Success)
                {
                    string assetPath = match.Groups[1].Value;
                    if (assetPath + "/" == needRemovePath)
                    {
                        continue;
                    }

                    if (assetPath.Length - needRemovePath.Length < 0)
                    {
                        UnityEngine.Debug.LogException(new System.Exception("length error:  " + assetPath + "  " + assetPath.Length + "  " + needRemovePath + "  " + needRemovePath.Length));
                    }

                    assetPath = assetPath.Substring(needRemovePath.Length, assetPath.Length - needRemovePath.Length);
//                    if (assetPath.EndsWith(".meta"))
//                    {
//                        assetPath = assetPath.Substring(0, assetPath.Length - 5);
//                    }

                    modifiedPathSet.Add(assetPath);
                }
            }
        }

        return modifiedPathSet;
    }

    public static HashSet<string> GetCurrentModifiedFileSet()
    {
        HashSet<string> modifiedPathSet = new HashSet<string>();

        string output = null;
        string err = null;
        int exitCode = CommandLineTool.CmdWithOutput(GetSvnPath(), "st", ref output, ref err);



        if (!string.IsNullOrEmpty(err))
        {
            throw new System.Exception(err);
        }

        //                Debug.LogError("test svn: " + output);

        System.Text.RegularExpressions.Regex regex = new System.Text.RegularExpressions.Regex(@"^[ ]*[^ ]+[ ]*(.*)");


        System.IO.StringReader strReader = new System.IO.StringReader(output);
        while (true)
        {
            string line = strReader.ReadLine();
            if (line == null)
            {
                break;
            }

            System.Text.RegularExpressions.Match match = regex.Match(line);
            if (match.Success)
            {
                string assetPath = match.Groups[1].Value;

                modifiedPathSet.Add(assetPath);
            }
        }

        return modifiedPathSet;
    }

    public static int GetLastChangedVersion(string path)
    {
        string output = null;
        string err = null;
        int exitCode = CommandLineTool.CmdWithOutput(GetSvnPath(), "info --show-item last-changed-revision " + path, ref output, ref err);
        if (exitCode != 0)
        {
            return -1;
        }

        return int.Parse(output);
    }

    public static string MergeToVersion(string path, int version, string otherParams = null)
    {
        string output = null;
        string err = null;
        string param = "merge -r BASE:" + version + " " + path + "  " + path + "  " + otherParams;
        int exitCode = CommandLineTool.CmdWithOutput(GetSvnPath(), param, ref output, ref err);
        return exitCode == 0? null: err;
    }
}